/**
 * 超时管理器 - 智能超时控制和重试机制
 */

const { createLogger } = require('../../logger');

const logger = createLogger('timeout-manager');

class TimeoutManager {
    constructor() {
        this.defaultTimeouts = {
            singleImage: 60000,      // 单图片分析：60秒
            doubleImage: 120000,     // 双图片对比：120秒
            modelList: 30000,        // 模型列表：30秒
            simpleAnalysis: 30000,   // 简单分析：30秒
            complexAnalysis: 90000   // 复杂分析：90秒
        };

        this.adaptiveSettings = {
            enabled: true,
            maxTimeout: 300000,      // 最大超时：5分钟
            minTimeout: 10000,       // 最小超时：10秒
            timeoutMultiplier: 1.5,  // 超时倍数
            consecutiveTimeouts: new Map() // 连续超时计数
        };
    }

    /**
     * 获取智能超时时间
     * @param {string} taskType - 任务类型
     * @param {Object} context - 上下文信息
     * @returns {number} - 超时时间（毫秒）
     */
    getSmartTimeout(taskType, context = {}) {
        const baseTimeout = this.defaultTimeouts[taskType] || this.defaultTimeouts.singleImage;

        if (!this.adaptiveSettings.enabled) {
            return baseTimeout;
        }

        // 根据上下文调整超时时间
        let adjustedTimeout = baseTimeout;

        // 1. 根据图片大小调整
        if (context.imageSize) {
            const sizeMB = context.imageSize / (1024 * 1024);
            if (sizeMB > 2) {
                adjustedTimeout *= 1.5; // 大图片增加50%超时时间
            } else if (sizeMB > 1) {
                adjustedTimeout *= 1.2; // 中等图片增加20%超时时间
            }
        }

        // 2. 根据提示词复杂度调整
        if (context.promptLength) {
            if (context.promptLength > 2000) {
                adjustedTimeout *= 1.3; // 长提示词增加30%超时时间
            } else if (context.promptLength > 1000) {
                adjustedTimeout *= 1.1; // 中等提示词增加10%超时时间
            }
        }

        // 3. 根据历史超时情况调整
        const contextKey = this.getContextKey(context);
        const consecutiveTimeouts = this.adaptiveSettings.consecutiveTimeouts.get(contextKey) || 0;

        if (consecutiveTimeouts > 0) {
            adjustedTimeout *= Math.pow(this.adaptiveSettings.timeoutMultiplier, Math.min(consecutiveTimeouts, 3));
        }

        // 4. 限制在最大最小值范围内
        adjustedTimeout = Math.max(
            this.adaptiveSettings.minTimeout,
            Math.min(this.adaptiveSettings.maxTimeout, adjustedTimeout)
        );

        logger.debug(`智能超时计算: ${taskType} 基础=${baseTimeout}ms 调整后=${adjustedTimeout}ms (连续超时: ${consecutiveTimeouts})`);

        return Math.round(adjustedTimeout);
    }

    /**
     * 记录超时事件
     * @param {string} taskType - 任务类型
     * @param {Object} context - 上下文信息
     * @param {number} actualTimeout - 实际超时时间
     */
    recordTimeout(taskType, context, actualTimeout) {
        const contextKey = this.getContextKey(context);
        const currentCount = this.adaptiveSettings.consecutiveTimeouts.get(contextKey) || 0;
        this.adaptiveSettings.consecutiveTimeouts.set(contextKey, currentCount + 1);

        logger.warn(`记录超时事件: ${taskType} (${contextKey}) 连续超时次数: ${currentCount + 1}, 实际超时: ${actualTimeout}ms`);

        // 如果连续超时次数过多，自动调整该上下文的默认超时时间
        if (currentCount >= 2) {
            this.adjustDefaultTimeout(taskType, context);
        }
    }

    /**
     * 记录成功事件
     * @param {string} taskType - 任务类型
     * @param {Object} context - 上下文信息
     * @param {number} duration - 执行时间
     */
    recordSuccess(taskType, context, duration) {
        const contextKey = this.getContextKey(context);
        this.adaptiveSettings.consecutiveTimeouts.delete(contextKey);

        logger.debug(`记录成功事件: ${taskType} (${contextKey}) 执行时间: ${duration}ms`);

        // 如果执行时间明显短于超时时间，可以考虑优化
        const currentTimeout = this.defaultTimeouts[taskType];
        if (duration < currentTimeout * 0.3) {
            logger.info(`建议优化: ${taskType} 执行时间(${duration}ms)远小于超时时间(${currentTimeout}ms)`);
        }
    }

    /**
     * 调整默认超时时间
     * @param {string} taskType - 任务类型
     * @param {Object} context - 上下文信息
     */
    adjustDefaultTimeout(taskType, context) {
        const currentTimeout = this.defaultTimeouts[taskType];
        const newTimeout = Math.round(currentTimeout * this.adaptiveSettings.timeoutMultiplier);

        if (newTimeout <= this.adaptiveSettings.maxTimeout) {
            this.defaultTimeouts[taskType] = newTimeout;
            logger.info(`自动调整默认超时时间: ${taskType} ${currentTimeout}ms -> ${newTimeout}ms`);
        } else {
            logger.warn(`已达最大超时限制，无法继续调整: ${taskType} ${currentTimeout}ms`);
        }
    }

    /**
     * 获取上下文键
     * @param {Object} context - 上下文信息
     * @returns {string} - 上下文键
     */
    getContextKey(context) {
        const parts = [];

        if (context.provider) parts.push(context.provider);
        if (context.model) parts.push(context.model);
        if (context.taskType) parts.push(context.taskType);

        return parts.join('-') || 'unknown';
    }

    /**
     * 创建带超时控制的Promise
     * @param {Promise} promise - 要包装的Promise
     * @param {number} timeout - 超时时间
     * @param {Object} context - 上下文信息
     * @returns {Promise} - 带超时控制的Promise
     */
    createTimeoutPromise(promise, timeout, context = {}) {
        const startTime = Date.now();

        return new Promise(async (resolve, reject) => {
            const controller = new AbortController();
            const timeoutId = setTimeout(() => {
                controller.abort();
                const duration = Date.now() - startTime;
                this.recordTimeout(context.taskType || 'unknown', context, duration);

                reject(new Error(`请求超时 (${timeout/1000}秒): ${context.description || '未知任务'}`));
            }, timeout);

            try {
                const result = await promise;
                clearTimeout(timeoutId);

                const duration = Date.now() - startTime;
                this.recordSuccess(context.taskType || 'unknown', context, duration);

                resolve(result);
            } catch (error) {
                clearTimeout(timeoutId);

                // 如果是超时错误，已经记录过了
                if (error.name !== 'AbortError') {
                    const duration = Date.now() - startTime;
                    logger.debug(`任务执行失败: ${context.taskType || 'unknown'} (${duration}ms): ${error.message}`);
                }

                reject(error);
            }
        });
    }

    /**
     * 获取当前超时设置
     * @returns {Object} - 超时设置
     */
    getTimeoutSettings() {
        return {
            defaultTimeouts: { ...this.defaultTimeouts },
            adaptiveSettings: { ...this.adaptiveSettings },
            consecutiveTimeouts: Object.fromEntries(this.adaptiveSettings.consecutiveTimeouts)
        };
    }

    /**
     * 重置超时设置
     */
    resetTimeoutSettings() {
        this.defaultTimeouts = {
            singleImage: 60000,
            doubleImage: 120000,
            modelList: 30000,
            simpleAnalysis: 30000,
            complexAnalysis: 90000
        };

        this.adaptiveSettings.consecutiveTimeouts.clear();
        logger.info('超时设置已重置为默认值');
    }

    /**
     * 更新自适应设置
     * @param {Object} newSettings - 新的设置
     */
    updateAdaptiveSettings(newSettings) {
        this.adaptiveSettings = {
            ...this.adaptiveSettings,
            ...newSettings
        };
        logger.info('自适应设置已更新');
    }
}

module.exports = TimeoutManager;